import { Context } from 'koa';
import jwt from 'jsonwebtoken';
import { v4 as uuidv4 } from 'uuid';
import { config } from '../config';
import User from '../models/User';
import { redisClient } from '../database';
import { AppError } from '../middlewares/errorHandler';

/**
 * 用户登录
 * @param ctx Koa上下文
 */
export const login = async (ctx: Context) => {
  const { username, password } = ctx.request.body;

  // 验证请求体
  if (!username || !password) {
    throw new AppError('用户名和密码不能为空', 400);
  }

  // 查找用户
  const user = await User.findOne({ where: { username } });

  // 验证用户是否存在
  if (!user) {
    throw new AppError('用户不存在', 404);
  }

  // 验证密码
  const isMatch = await user.comparePassword(password);
  if (!isMatch) {
    throw new AppError('密码错误', 401);
  }

  // 验证用户状态
  if (user.status !== 'active') {
    throw new AppError('账号已被禁用', 403);
  }

  // 更新最后登录时间
  user.last_login = new Date();
  await user.save();

  // 生成Token
  const token = generateToken(user.id);

  // 保存Token到Redis，用于后续的验证和刷新
  await redisClient.set(`token:${user.id}`, token, {
    EX: 60 * 60 * 24 * 7, // 7天过期
  });

  // 返回用户信息和Token
  ctx.body = {
    status: 'success',
    message: '登录成功',
    data: {
      token,
      user: {
        id: user.id,
        username: user.username,
        nickname: user.nickname,
        email: user.email,
        avatar: user.avatar,
        role: user.role,
      },
    },
  };
};

/**
 * 用户注册
 * @param ctx Koa上下文
 */
export const register = async (ctx: Context) => {
  const { username, password, email, nickname } = ctx.request.body;

  // 验证请求体
  if (!username || !password || !email) {
    throw new AppError('用户名、密码和邮箱不能为空', 400);
  }

  // 检查用户名是否已存在
  const existingUser = await User.findOne({ where: { username } });
  if (existingUser) {
    throw new AppError('用户名已存在', 409);
  }

  // 检查邮箱是否已存在
  const existingEmail = await User.findOne({ where: { email } });
  if (existingEmail) {
    throw new AppError('邮箱已存在', 409);
  }

  // 创建新用户
  const user = await User.create({
    id: uuidv4(),
    username,
    password,
    email,
    nickname: nickname || username,
    role: 'user',
    status: 'active',
  });

  // 生成Token
  const token = generateToken(user.id);

  // 保存Token到Redis
  await redisClient.set(`token:${user.id}`, token, {
    EX: 60 * 60 * 24 * 7, // 7天过期
  });

  // 返回用户信息和Token
  ctx.body = {
    status: 'success',
    message: '注册成功',
    data: {
      token,
      user: {
        id: user.id,
        username: user.username,
        nickname: user.nickname,
        email: user.email,
        avatar: user.avatar,
        role: user.role,
      },
    },
  };
};

/**
 * 获取当前用户信息
 * @param ctx Koa上下文
 */
export const getUserInfo = async (ctx: Context) => {
  // 从ctx.state中获取用户ID（由auth中间件设置）
  const userId = ctx.state.user.id;

  // 查找用户
  const user = await User.findByPk(userId);

  // 验证用户是否存在
  if (!user) {
    throw new AppError('用户不存在', 404);
  }

  // 返回用户信息
  ctx.body = {
    status: 'success',
    data: {
      user: {
        id: user.id,
        username: user.username,
        nickname: user.nickname,
        email: user.email,
        avatar: user.avatar,
        role: user.role,
        status: user.status,
        last_login: user.last_login,
      },
    },
  };
};

/**
 * 刷新Token
 * @param ctx Koa上下文
 */
export const refreshToken = async (ctx: Context) => {
  const { token } = ctx.request.body;

  if (!token) {
    throw new AppError('Token不能为空', 400);
  }

  try {
    // 验证Token
    const decoded: any = jwt.verify(token, config.jwt.secret);

    // 从Redis获取保存的Token
    const savedToken = await redisClient.get(`token:${decoded.id}`);

    // 验证Token是否存在于Redis
    if (!savedToken || savedToken !== token) {
      throw new AppError('无效的Token', 401);
    }

    // 生成新的Token
    const newToken = generateToken(decoded.id);

    // 更新Redis中的Token
    await redisClient.set(`token:${decoded.id}`, newToken, {
      EX: 60 * 60 * 24 * 7, // 7天过期
    });

    // 返回新的Token
    ctx.body = {
      status: 'success',
      message: 'Token刷新成功',
      data: {
        token: newToken,
      },
    };
  } catch (error) {
    throw new AppError('Token无效或已过期', 401);
  }
};

/**
 * 退出登录
 * @param ctx Koa上下文
 */
export const logout = async (ctx: Context) => {
  // 从ctx.state中获取用户ID（由auth中间件设置）
  const userId = ctx.state.user.id;

  // 从Redis删除Token
  await redisClient.del(`token:${userId}`);

  ctx.body = {
    status: 'success',
    message: '退出登录成功',
  };
};

/**
 * 生成JWT Token
 * @param userId 用户ID
 * @returns JWT Token
 */
const generateToken = (userId: string): string => {
  return jwt.sign(
    {
      id: userId,
    },
    config.jwt.secret,
    {
      expiresIn: config.jwt.expiresIn,
    }
  );
}; 